from django_redis import get_redis_connection
from rest_framework import serializers
from itsdangerous import TimedJSONWebSignatureSerializer as TJS
from rest_framework_jwt.settings import api_settings

from oauth.models import OAuthQQUser
from users.models import User
import re
from django.conf import settings


class QQAuthUserSerializer(serializers.ModelSerializer):
    # 不是模型字段，需要显示指明字段
    sms_code = serializers.CharField(max_length=6, min_length=6, write_only=True)
    access_token = serializers.CharField(write_only=True)
    # 模型中的序列化字段不满足需求，可以进行重写
    mobile = serializers.RegexField(label='手机号', regex=r'^1[3-9]\d{9}$')
    token = serializers.CharField(read_only=True)

    class Meta:
        model = User
        fields = ('password', 'mobile', 'sms_code', 'access_token', 'username', 'token')
        read_only_fields = ('username',)  # 指定只读，序列化返回
        extra_kwargs = {
            'password': {
                'max_length': 20,
                'min_length': 8,
                'write_only': True,
                'error_messages': {
                    'max_length': '密码过长'
                }
            },
            'mobile': {
                'max_length': 11,
                'min_length': 11,
                'error_messages': {
                    'max_length': '手机号格式错误',
                    'min_length': '手机号格式错误'
                }
            },

        }

    # 对手机号验证
    def validated_mobile(self, value):
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机格式不正确')
        return value

    # 多个字段进行验证
    def validate(self, attrs):
        # 一：access_token
        # 解密acess_token
        tjs = TJS(settings.SECRET_KEY, 300)
        try:
            data = tjs.loads(attrs['access_token'])
        except:
            raise serializers.ValidationError('错误的access_token')

        openid = data.get('openid')
        # attrs添加额外属性，方便保存数据时进行提取（对已经注册的用户进行绑定）
        attrs['openid'] = openid

        # 二：验证短信
        # 1.建立链接
        conn = get_redis_connection('verify')

        # 2.获取数据（bytes类型）
        real_sms_code = conn.get('sms_%s' % attrs['mobile'])
        # 判断验证码是否过期
        if not real_sms_code:
            raise serializers.ValidationError('短信失效')

        # 3.转换数据格式为字符串
        real_sms_code = real_sms_code.decode()

        # 4.对比验证
        if attrs['sms_code'] != real_sms_code:
            raise serializers.ValidationError('短信有误')

        # 三：验证用户
        try:
            user = User.objects.get(mobile=attrs['mobile'])
        except:
            return attrs

        else:
            # 校验密码
            if user.check_password(attrs['password']):
                attrs['user'] = user
                return attrs
            else:
                raise serializers.ValidationError('密码错误')

    # 保存用户数据
    def create(self, validated_data):
        # 获取user数据判断是否注册
        user = validated_data.get('user', None)

        if user is None:
            # 用户未注册  需要注册新用户
            user = User.objects.create_user(username=validated_data['mobile'], password=validated_data['password'],
                                            mobile=validated_data['mobile'])

        # 用户已注册，绑定用户（openid）
        OAuthQQUser.objects.create(user=user, openid=validated_data['openid'])
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        # 对user对象添加token属性字段
        user.token = token

        self.context['view'].user = user

        # 返回用户信息
        return user
